﻿#ifndef MODBUSRTU_H
#define MODBUSRTU_H

#include <QObject>
#include <QWidget>
#include <QListWidget>
#include <QDateTime>
#include <QApplication>
#include <QDebug>
#include <QFile>

#include <iostream>
#include <vector>

using namespace std;

#include "serialport.h"

#define u8 uint8_t
#define u16 uint16_t

class ModbusRTU : public SerialPort
{
public:
    ModbusRTU(QListWidget *listwidget = 0);

public:
    /* modbus rtu 03 读寄存器命令组帧函数
     * cmd 为命令地址
     * addr 为要读取的寄存器地址
     * len 为读取的寄存器长度
     * 返回值：空
     */
    void ModbusRTU_03(QByteArray &cmd, uint8_t *addr, uint16_t len);
    /*
     * modbus rtu 10 写多个寄存器组帧函数
     * cmd为命令地址
     * addr为要写的寄存器地址
     * len为要写的寄存器长度
     * data为写入的数据
     * 返回值：空
     */
    void ModbusRTU_10(QByteArray &cmd, uint8_t *addr, uint16_t len, uint8_t *data);
    /*
     * modbus 发送函数
     * port 串口
     * snd 发送的命令帧
     * rcv 收到的数据帧
     * 返回值：正确返回true，反之返回false
     */
    bool ModbusRTUSend(QSerialPort *port, QByteArray snd, QByteArray &rcv);
    /*
     * modbus 03命令返回的值
     * port 串口
     * addr 寄存器地址
     * len  读取的寄存器长度
     * value 保存得到的值
     */
    void ModbusRTU_03_GetValue(QSerialPort *port, uint8_t *addr, uint16_t len, vector<uint8_t> &value);

    // modbus响应延时时间
    void changeResponDelayTime(int nums);

    /*
     * 自动编写通讯报文，用于测试继电器及多机通讯时使用
     * nums 连接在485总线的机器数量
     */
    QByteArray AutoWriteModbus(int nums, QByteArray cmd);
    /*
     *  修改Modbus通讯地址
     */
    void ChangeModbusAddr(uint8_t newAddr);

private:
    void ShowSndMessage(QByteArray snd);
    void ShowRcvMessage(QByteArray rcv);
    void MyDelay(int msecs);

    u16 CalcCRCModBus(u8 cDataIn, u16 wCRCIn);
public:
    u16 GetCRCModBus(u8 *pDataIn, u8 iLenIn);
    bool CheckCRCModbus(u8 *pDataIn, u8 iLenIn);

private:
    QListWidget *MessageListWidget;
    SerialPort sp;
    int responDelayTime;
    uint8_t modbusAddr;
};

#endif // MODBUSRTU_H
